package pzl.kt.study.base

import org.junit.Test
import java.util.*

fun isEvent(a: Int) = a % 2 == 0

//lambda 和高阶函数
//匿名函数，没有函数名的函数，闭包
//｛ 参数1，参数2，参数n... -> 执行语句 ｝
class LambdaHighFunc {


    @Test
    fun test1() {
        println(add1(1, 2))
        println(add2(4, 3))
        println(add2Value(44, 55, add2))
        println(计算乘法(4, 6, { a, b -> a * b }))
    }


    //普通函数
    fun add1(x: Int, y: Int): Int {
        return x + y
    }

    //lambda 赋值给变量
    var add2 = { x: Int, y: Int -> x + y }

    //函数类型的参数（lambda）,有点像c语言函数指针
    //注意函数参数的函数返回类型 ： 变成了 ->
    fun add2Value(x: Int, y: Int, addFunc: (a: Int, b: Int) -> Int): Int {
        return addFunc(x, y)
    }

    fun 计算乘法(x: Int, y: Int, method: (a: Int, b: Int) -> Int): Int {
        return method(x, y)
    }


    //接受参数是函数类型的函数，或返回类型是函数类型的函数  称之为高阶函数 （如上例参数为函数类型的函数）
    @Test
    fun test2() {
        var v = getFun()("\n")
        println(v)
    }

    var simpleStringFun = { s: String -> Date().toLocaleString().replace("-", s) }
    fun getFun(): (msg: String) -> String {
        return simpleStringFun
    }

    //顶层函数引用
    //public inline fun <T> Array<out T>.filter(predicate: (T) -> Boolean): List<T> {
    //    return filterTo(ArrayList<T>(), predicate)
    //}
    @Test
    fun test3() {
        //对于filter这样的高阶函数，如果有一个已定义好的顶层函数（闭包之外的函数），可以用一下两种方式来引用
        var aar1 = arrayOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 11).filter { isEvent(it) }
        println(aar1)
        var aar2 = arrayOf(-1, -2, -3, -4, -5, -6, -7, -8, -9).filter(::isEvent)
        println(aar2)
    }


    //成员函数引用
    @Test
    fun test4() {
        //这里min是Math的成员函数
        val minVlaue = comboTwoValue(1, 2) { a, b -> Math.min(a, b) } //写到外面去了。。。
        println("minVlaue = " + minVlaue)
        //可简化成下面的方式
        val minValue2 = comboTwoValue(111, 444, Math::min)
        println("minVlaue2 = " + minValue2)
    }

    fun comboTwoValue(x: Int, y: Int, method: (a: Int, b: Int) -> Int): Int {
        return method(x, y)
    }

    //扩展函数的引用
    //public inline fun <T> Array<out T>.filter(predicate: (T) -> Boolean): List<T> {
    //    return filterTo(ArrayList<T>(), predicate)
    //}
    @Test
    fun test5() {
        //Int扩展，奇数判断
        fun Int.isOdd() = this % 2 != 0

        val allOddNumbers = arrayOf(4, 1, 67, 4, 12, 34, 86, 34, 5, 7343).filter(Int::isOdd)
        println(allOddNumbers)
        //如果引用的函数有2个参数，可把第二个参数提前
        val ss = arrayOf("kotlin", "java", "c++", "grovy")
        val match = ss.filter("java"::equals)
        println(match)
    }


}